/**************************************************************************
 *
 * Copyright 2014 MaeckySoft Ltd., Bludenz, Austria.
 * All Rights Reserved.
 *
 **************************************************************************/
#include "MFontTexture.h"
#include <iostream>
#include <fstream>

#define _PNGExt ".png"
#define _ATTExt ".gly"

MFontTexture::MFontTexture(int iDebug) :M3DBase(iDebug)
{

	m_sCharSet = "ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,-_+*%$!#/?@<>()[]{}";
    m_MFTMMainFontManager = NULL;

	if (iDebug >= MDBG_VERBOSE) std::cout << "(" << __FILE__ << ") <DBG_VERBOSE> " << __PRETTY_FUNCTION__ << " called." << std::endl;

    //ctor
}

MGlyph* MFontTexture::getGlyphFromChar(char cCharacter)
{
    MGlyph *ret=NULL;
    std::map<char, MGlyph*>::iterator tmp = m_mapGlyphs.find(cCharacter);
    if (tmp != m_mapGlyphs.end())
    {
        ret = tmp->second;
    }
    return ret;
}

std::map<char, MGlyph*> *MFontTexture::getGlyphMap()
{
    return &m_mapGlyphs;
}

void MFontTexture::setRenderCharSet(std::string sCharSet)
{
    if (sCharSet !="") m_sCharSet = sCharSet;
}

std::string MFontTexture::getRenderCharSet()
{
    return m_sCharSet;
}

void MFontTexture::setFontSize(int iFontSize)
{
    m_iFontSize = iFontSize;
}

int MFontTexture::getFontSize()
{
    return m_iFontSize;
}

std::string MFontTexture::getFont()
{
    if (m_iDebug >= MDBG_ALL) this->printMethodInfo(__PRETTY_FUNCTION__);
    return m_sFontName;
}

void MFontTexture::setFont(std::string sFontName)
{
    if (m_iDebug >= MDBG_ALL) this->printMethodInfo(__PRETTY_FUNCTION__);
    m_sFontName = sFontName;
}

std::string MFontTexture::getOutputFileName()
{
    if (m_iDebug >= MDBG_ALL) this->printMethodInfo(__PRETTY_FUNCTION__);
    return m_sOutputFile;
}

void MFontTexture::setOutputFileName(std::string sFileName)
{
    if (m_iDebug >= MDBG_ALL) this->printMethodInfo(__PRETTY_FUNCTION__);
    m_sOutputFile = sFileName;
}

int MFontTexture::renderCharSet()
{
        if (m_iDebug >= MDBG_ALL) this->printMethodInfo(__PRETTY_FUNCTION__);
        int iError=0;
        m_MFTMMainFontManager = new MFTManager(m_iDebug);
        iError = m_MFTMMainFontManager->initFT();
        if (iError != 0) {
            delete(m_MFTMMainFontManager);
            m_MFTMMainFontManager = NULL;
            return iError;
        }
        iError = m_MFTMMainFontManager->loadFont(T(m_sFontName.c_str()));
        if (iError != 0) {
            delete(m_MFTMMainFontManager);
            m_MFTMMainFontManager = NULL;
            return iError;
        }
        iError = m_MFTMMainFontManager->setFontSize(m_iFontSize);
        if (iError != 0) {
            delete(m_MFTMMainFontManager);
            m_MFTMMainFontManager = NULL;
            return iError;
        }

        unsigned int i=0;
        MGlyph *tmpGlyph=NULL;
        char tmpChar;
        while (i< m_sCharSet.length())
        {
            tmpChar = m_sCharSet[i++];
            tmpGlyph = m_MFTMMainFontManager->renderCharacter(tmpChar);
            tmpGlyph->renderRGBA();
            if (tmpGlyph != NULL)
            {
                m_mapGlyphs.insert(std::pair<char, MGlyph*> (tmpChar, tmpGlyph));
            }
            else{
                if (tmpGlyph!=NULL) delete(tmpGlyph);
                std::map<char,MGlyph*>::iterator it;

                for (std::map<char,MGlyph*>::iterator it=m_mapGlyphs.begin(); it!=m_mapGlyphs.end(); ++it)
                {
                    if (it->second != NULL) delete(it->second);
                }
                m_mapGlyphs.clear();
                iError = 1;
                i=65537;
            }

        }
        delete(m_MFTMMainFontManager);
        m_MFTMMainFontManager = NULL;

        return iError;

}


int MFontTexture::packCharSet()
{
	int iWidth = this->calculateImageWidth();
	int iHeight = this->calculateImageHeight();
	int iBPP = MPNG_RGBA;
	int iGlyphWidth = 0;
	int iGlyphHeight = 0;
	int iWidthPos = 0;
	unsigned char *gBuff;
	std::ofstream f_attfile;

	std::string sATTFile = m_sOutputFile;
	sATTFile.append(T(_ATTExt));
	std::string sPNGFile = m_sOutputFile;
	sPNGFile.append(T(_PNGExt));

    // write glyph attributes to sATTFile


	f_attfile.open(sATTFile.c_str(),std::ofstream::out);
	f_attfile << "Character;Height;Width;PointSize;Advance;BearingX;BearingY" << std::endl;

	MPNG* p = new MPNG(iWidth, iHeight, iBPP, m_iDebug);
	unsigned char *b = new unsigned char[iBPP * iWidth * iHeight];
	memset(b, 0, iBPP*iWidth*iHeight);
	// read glyphs and pack them into buffer
	std::map<char, MGlyph*>::iterator it;

	for (std::map<char, MGlyph*>::iterator it = m_mapGlyphs.begin(); it != m_mapGlyphs.end(); ++it)
	{
		MGlyph *t;
		t = (MGlyph *)it->second;
		gBuff = t->getImageRGBA();
		iGlyphWidth = t->getWidth();
		iGlyphHeight = t->getHeight();
		// write Glyph attributes to file
		f_attfile << t->getCharacter() << ";";
		f_attfile << t->getHeight() << ";";
		f_attfile << t->getWidth() << ";";
		f_attfile << t->getPointSize() << ";";
		f_attfile << t->getAdvance() << ";";
		f_attfile << t->getBearingX() << ";";
		f_attfile << t->getBearingY() << std::endl;


		for (int i = 0; i < iGlyphHeight; i++)
		{
			memcpy(&b[(iWidth*4 * i + iWidthPos)], &gBuff[(i * iGlyphWidth*4)], iGlyphWidth*4);


		}
		iWidthPos += iGlyphWidth*4;
	}

	// write buffer into PNG
	p->setBuffer(b);
	p->writeFile(sPNGFile);
	f_attfile.close();
	delete(b);
	delete (p);
	return 0;
}

long MFontTexture::setXYPos(int x, int y, int linewidth)
{
	return linewidth * y + x;
}

int MFontTexture::getMaxGlyphHeight()
{
	int iMaxGlyphHeight = 0;
	int itmpHeight = 0;
	std::map<char, MGlyph*>::iterator it;

	for (std::map<char, MGlyph*>::iterator it = m_mapGlyphs.begin(); it != m_mapGlyphs.end(); ++it)
	{
		MGlyph *t;
		t = (MGlyph *)it->second;
		itmpHeight = t->getHeight();
		if (itmpHeight > iMaxGlyphHeight) iMaxGlyphHeight = itmpHeight;
	}

	return iMaxGlyphHeight;
}
int MFontTexture::getMaxGlyphWidth()
{
	int iMaxGlyphWidth = 0;
	int itmpWidth = 0;
	std::map<char, MGlyph*>::iterator it;

	for (std::map<char, MGlyph*>::iterator it = m_mapGlyphs.begin(); it != m_mapGlyphs.end(); ++it)
	{
		MGlyph *t;
		t = (MGlyph *)it->second;
		itmpWidth = t->getHeight();
		if (itmpWidth > iMaxGlyphWidth) iMaxGlyphWidth = itmpWidth;
	}

	return iMaxGlyphWidth;
}
int MFontTexture::calculateImageHeight()
{
	return this->getMaxGlyphHeight();
}
int MFontTexture::calculateImageWidth()
{
	int iImageWidth = 0;
	int itmpWidth = 0;
	std::map<char, MGlyph*>::iterator it;

	for (std::map<char, MGlyph*>::iterator it = m_mapGlyphs.begin(); it != m_mapGlyphs.end(); ++it)
	{
		MGlyph *t;
		t = (MGlyph *)it->second;
		itmpWidth = t->getWidth();
		iImageWidth += itmpWidth;
	}
	return iImageWidth;
}

void MFontTexture::printMethodInfo(std::string method)
{
	if (m_iDebug == MDBG_ALL) std::cout << "(" << __FILE__ << ") <DBG_ALL> " << method << " called." << std::endl;
}


MFontTexture::~MFontTexture()
{
	if (m_iDebug >= MDBG_VERBOSE) std::cout << "(" << __FILE__ << ") <DBG_VERBOSE> " << __PRETTY_FUNCTION__ << " called." << std::endl;

    std::map<char,MGlyph*>::iterator it;

    for (std::map<char,MGlyph*>::iterator it=m_mapGlyphs.begin(); it!=m_mapGlyphs.end(); ++it)
    {
        MGlyph *t;
        t = (MGlyph *)it->second;
        delete t;
    }
    m_mapGlyphs.clear();
    if (m_MFTMMainFontManager != NULL) delete(m_MFTMMainFontManager);
    //dtor
}
